package com.example.demo.service;

import com.example.demo.core.ElasticsearchOperationUtils;
import com.example.demo.core.HtmlParseUtils;
import com.example.demo.domain.Goods;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author Shanks
 * @date 2020-05-26
 */
@Service
public class JdGoodsService {

    @Resource
    private HtmlParseUtils htmlParseUtils;

    @Resource
    private ElasticsearchOperationUtils elasticsearchOperationUtils;

    @Resource
    private RestHighLevelClient restHighLevelClient;

    public boolean initGoods(String keyword) throws IOException {
        List<Goods> goodsList = htmlParseUtils.getGoodsListFromJd(keyword);
        return elasticsearchOperationUtils.insertBulkSyncData("jd_goods", "_doc", goodsList, "sku");
    }

    public List<Map<String, Object>> searchPage(String keyword, Integer pageNo, Integer pageSize) throws IOException {
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 因为在es的mapping中, title字段类型为text, 采用的又是默认的分词, 所以页面查询java, 是可以查到分词后的java单词的
        // 正常的开发中, 查询一般走的是BoolQueryBuilder
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
        searchSourceBuilder.query(termQueryBuilder);
        searchSourceBuilder.timeout(TimeValue.timeValueSeconds(6));

        searchSourceBuilder.from(pageNo);
        searchSourceBuilder.size(pageSize);

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        // 支持多个高亮设置为true, 比如一段文字有多个java单词, 若设置false, 则只高亮第一个java单词
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.field("title");
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        searchSourceBuilder.highlighter(highlightBuilder);

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits searchHits = searchResponse.getHits();
        SearchHit[] searchHitArr = searchHits.getHits();
        List<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit searchHit : searchHitArr) {
            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();

            // 解析高亮字段
            Map<String, HighlightField> highlightFieldMap = searchHit.getHighlightFields();
            HighlightField title = highlightFieldMap.get("title");
            if (Objects.nonNull(title)) {
                Text[] fragments = title.fragments();
                StringBuilder newTitle = new StringBuilder();
                for (Text fragment : fragments) {
                    newTitle.append(fragment.string());
                }
                // 替换即可
                sourceAsMap.put("title", newTitle);
            }

            list.add(sourceAsMap);
        }
        return list;
    }
}